package com.leqicheng.tenon;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;

import org.apache.http.Header;

import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.widget.Toast;

import com.alibaba.fastjson.JSON;
import com.leqicheng.tenon.updata.FileDownloadThread;
import com.leqicheng.tenon.updata.UpdataHttpRequest;
import com.leqicheng.tenon.util.GeneralCallBack;
import com.leqicheng.tenon.util.RequestStatus;
import com.leqicheng.tenon.util.RequestTypeEnum;

public class GameLoader implements GeneralCallBack {

    private Context mContext;
    private String mChannelKey = "";
    private String mUserId;
    private String mGameKey;

    private int downloadedSize = 0;
    private int fileSize = 0;
    private boolean download = false;
    private String mGameIconUrl;
    private static String BASE_DOWNLOAD_URL = "https://tenon-x.com/";
    private static String BASE_FILENAME = "Tenon";
    private static String PACKAGENAME = "com.leqicheng.tenon";

    public GameLoader(Context mContext, String mChannelKey, String mGameKey,
            String mUserId) {
        super();
        this.mContext = mContext;
        this.mChannelKey = mChannelKey;
        this.mUserId = mUserId;
        this.mGameKey = mGameKey;

    }

    public void startGame() {
        if (isAppInstalled(mContext, PACKAGENAME)) {
            openGameRuntime(PACKAGENAME, mGameKey);
        } else {
            registerBroadcast();
            UpdataHttpRequest updataHttpRequest = new UpdataHttpRequest(
                    mContext, this);
            updataHttpRequest.postRequest(null);
        }
    }

    private boolean isAppInstalled(Context context, String packagename) {
        PackageInfo packageInfo;
        try {
            packageInfo = context.getPackageManager().getPackageInfo(
                    packagename, 0);
        } catch (NameNotFoundException e) {
            packageInfo = null;
            e.printStackTrace();
        }
        if (packageInfo == null) {
            // System.out.println("没有安装");
            return false;
        } else {
            // System.out.println("已经安装");
            return true;
        }
    }

    private void download(String downloadUrl, String downloadFileName) {
        // 获取SD卡目录
        String dowloadDir = Environment.getExternalStorageDirectory()
                + "/tenon_runtime/";
        File file = new File(dowloadDir);
        // 创建下载目录
        if (!file.exists()) {
            file.mkdirs();
        }
        // 读取下载线程数，如果为空，则单线程下载
        int downloadTN = 1;
        // 如果下载文件名为空则获取Url尾为文件名
        int fileNameStart = downloadUrl.lastIndexOf("/");
        String fileName = "".equals(downloadFileName) ? downloadUrl
                .substring(fileNameStart) : downloadFileName;
        if (fileIsExists(dowloadDir + fileName)) {
            File tenonFile = new File(dowloadDir + fileName);
            openFile(tenonFile);
            return;
        }
        new downloadTask(downloadUrl, Integer.valueOf(downloadTN), dowloadDir
                + fileName).start();

    }

    // 判断文件是否存在
    public boolean fileIsExists(String strFile) {
        try {
            File f = new File(strFile);
            if (!f.exists()) {
                return false;
            }

        } catch (Exception e) {
            return false;
        }

        return true;
    }

    Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            // 当收到更新视图消息时，计算已完成下载百分比，同时更新进度条信息
            int progress = (Double
                    .valueOf((downloadedSize * 1.0 / fileSize * 100)))
                    .intValue();
            if (progress == 100) {
                openFile(file);
            }
        }

    };
    public File file;
    private BroadcastReceiver myBroadcastReceiver;

    /**
     * @author ideasandroid
     *         主下载线程
     */
    private class downloadTask extends Thread {
        private int blockSize, downloadSizeMore;
        private int threadNum = 5;
        String urlStr, threadNo, fileName;

        public downloadTask(String urlStr, int threadNum, String fileName) {
            Toast.makeText(mContext, "正在下载游戏运行环境", Toast.LENGTH_LONG).show();
            this.urlStr = urlStr;
            this.threadNum = threadNum;
            this.fileName = fileName;
        }

        @Override
        public void run() {
            FileDownloadThread[] fds = new FileDownloadThread[threadNum];
            try {
                URL url = new URL(urlStr);
                URLConnection conn = url.openConnection();
                // 获取下载文件的总大小
                fileSize = conn.getContentLength();
                // 计算每个线程要下载的数据量
                blockSize = fileSize / threadNum;
                // 解决整除后百分比计算误差
                downloadSizeMore = (fileSize % threadNum);
                file = new File(fileName);
                for (int i = 0; i < threadNum; i++) {
                    // 启动线程，分别下载自己需要下载的部分
                    FileDownloadThread fdt = new FileDownloadThread(url, file,
                            i * blockSize, (i + 1) * blockSize - 1);
                    fdt.setName("Thread" + i);
                    fdt.start();
                    fds[i] = fdt;
                }
                boolean finished = false;
                while (!finished) {
                    // 先把整除的余数搞定
                    downloadedSize = downloadSizeMore;
                    finished = true;
                    for (int i = 0; i < fds.length; i++) {
                        downloadedSize += fds[i].getDownloadSize();
                        if (!fds[i].isFinished()) {
                            finished = false;
                        }
                    }
                    // 通知handler去更新视图组件
                    handler.sendEmptyMessage(0);
                    // 休息1秒后再读取下载进度
                    sleep(500);
                }
            } catch (Exception e) {

            }

        }
    }

    private String filePath;

    private void openFile(File file) {
        if (isRoot()) {
            filePath = file.getPath();
            installHandler.sendMessage(new Message());
        } else {
            // TODO Auto-generated method stub
            installApk(file);
        }
    }

    private void installApk(File file) {
        Log.i("OpenFile", file.getName());
        Intent intent = new Intent();
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intent.setAction(android.content.Intent.ACTION_VIEW);
        intent.setDataAndType(Uri.fromFile(file),
                "application/vnd.android.package-archive");
        mContext.startActivity(intent);
    }

    Handler installHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            if (installSlient(mContext, filePath) != 0) {
                File file = new File(filePath);
                installApk(file);
            }
        }

    };

    /**
     * install slient
     * @param context
     * @param filePath
     * @return 0 means normal, 1 means file not exist, 2 means other exception
     *         error
     */
    public int installSlient(Context context, String filePath) {
        File file = new File(filePath);
        if (filePath == null || filePath.length() == 0
                || (file = new File(filePath)) == null || file.length() <= 0
                || !file.exists() || !file.isFile()) {
            return 1;
        }

        String[] args = { "pm", "install", "-r", filePath };
        ProcessBuilder processBuilder = new ProcessBuilder(args);

        Process process = null;
        BufferedReader successResult = null;
        BufferedReader errorResult = null;
        StringBuilder successMsg = new StringBuilder();
        StringBuilder errorMsg = new StringBuilder();
        int result = 10000;
        String s = "";
        try {
            process = processBuilder.start();
            successResult = new BufferedReader(new InputStreamReader(
                    process.getInputStream()));
            errorResult = new BufferedReader(new InputStreamReader(
                    process.getErrorStream()));

            while ((s = successResult.readLine()) != null) {
                successMsg.append(s);
            }

            while ((s = errorResult.readLine()) != null) {
                errorMsg.append(s);
            }
        } catch (IOException e) {
            e.printStackTrace();
            result = 2;
        } catch (Exception e) {
            e.printStackTrace();
            result = 2;
        } finally {
            try {
                if (successResult != null) {
                    successResult.close();
                }
                if (errorResult != null) {
                    errorResult.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            if (process != null) {
                process.destroy();
            }
        }

        // TODO should add memory is not enough here
        if (successMsg.toString().contains("Success")
                || successMsg.toString().contains("success")) {
            result = 0;
        } else {
            result = 2;
        }
        Log.d("installSlient", "successMsg:" + successMsg + ", ErrorMsg:"
                + errorMsg);
        return result;
    }

    public boolean isRoot() {
        boolean bool = false;
        try {
            if ((!new File("/system/bin/su").exists())
                    && (!new File("/system/xbin/su").exists())) {
                bool = false;
            } else {
                bool = true;
            }
        } catch (Exception e) {
        }
        return bool;
    }

    private void registerBroadcast() {
        download = true;
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction("android.intent.action.PACKAGE_REPLACED");
        intentFilter.addAction("android.intent.action.PACKAGE_ADDED"); // 为BroadcastReceiver指定action，即要监听的消息名字。
        intentFilter.addDataScheme("package");
        myBroadcastReceiver = new BroadcastReceiver() {

            @Override
            public void onReceive(Context context, Intent intent) {
                // 接收到广播后需要执行的代码
                // TODO Auto-generated method stub
                mContext.unregisterReceiver(myBroadcastReceiver);
                String packageName = intent.getData().getSchemeSpecificPart();
                if (packageName.equals("com.leqicheng.tenon")) {
                    openGameRuntime(packageName, mGameKey);
                }
            }
        };
        mContext.registerReceiver(myBroadcastReceiver, intentFilter); // 注册监听
    }

    private void openGameRuntime(String packageName, String gameKey) {
        ComponentName cn = new ComponentName(packageName, packageName
                + ".RuntimeActivity");
        Intent openIntent = new Intent();
        openIntent.setAction("start_tenon");
        Bundle bundle = new Bundle();
        bundle.putString("game_key", gameKey);
        bundle.putString("game_icon_url", mGameIconUrl);
        bundle.putString("channel_key", mChannelKey);
        if (mUserId != null) {
            bundle.putString("ChannelUserId", mUserId);
        }
        openIntent.setComponent(cn);
        openIntent.putExtras(bundle);
        mContext.startActivity(openIntent);
    }

    @Override
    public void onComplete(RequestTypeEnum requestType, int status,
            String responseBody) {
        switch (status) {
        case RequestStatus.NETWORK_ERROR:
            Toast.makeText(mContext, "网络错误", Toast.LENGTH_SHORT).show();
            break;
        case RequestStatus.OBTAIN_SUCCESS:
            String UpdataVersion = JSON.parseObject(responseBody).getString(
                    "version_id");
            String UpdataApkUrl = JSON.parseObject(responseBody).getString(
                    "address_url");
            String fileName = BASE_FILENAME + UpdataVersion + ".apk";
            download(UpdataApkUrl, fileName);
        default:
            break;
        }
    }

}
